package org.NooLab.itexx.app.gui.handlers.keys;

import java.awt.Component;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import javax.swing.JComponent;
import javax.swing.JFrame;

import org.NooLab.itexx.app.gui.handlers.WindowAppearanceIntf;
import org.NooLab.itexx.app.gui.handlers.WindowToggler;
import org.NooLab.itexx.browser.KeyCodes;



public class Keyhandler implements KeyHandlingCallbackIntf{

	ArrayList<String> observedKeys = new ArrayList<String>();
	
	Map<String,Object> actions = new HashMap<String,Object>();
	
	private Keyhandlers parent;
	private int id;

	private int lastPanelKey;

	private long lastPanelKeyTime;

	private long lastKeyDetectTime=-1L;
	
	// ========================================================================
	public Keyhandler(Keyhandlers parent, int id, String[] globalKeys) {
		
		this.parent = parent;
		this.id = id;
		if (globalKeys!=null){
		for (int i=0;i<globalKeys.length;i++){
			
			if (observedKeys.contains(globalKeys[i])==false){
				observedKeys.add( globalKeys[i] );
			}
		}
		}	
	}
	// ========================================================================
	
	public void addKey( String keystr){
		if (observedKeys.contains(keystr)==false){
			observedKeys.add( keystr );
		}
	}
	public void removeKey( String keystr){
		
	}
	public void removeAllKeys(){
		observedKeys.clear();
	}
	

	/*
	 * TODO: instead of a single variable for lastPanelKey, we need a int[2], for recognizing double option keys...
	 */
	@Override
	public void keyPressed(KeyEvent evt) {
	
		//parent.out.print(2, "object <id:"+id+"> observed key event: --- "+ evt);
		
		int currentKeyCode = evt.getKeyCode();
		if (currentKeyCode==16){
			parent.setCurrentControlFunctionKey(Keyhandlers._CFK_SHIFT, System.currentTimeMillis());
		}
		if (currentKeyCode==17){
			parent.setCurrentControlFunctionKey(Keyhandlers._CFK_CTRL, System.currentTimeMillis());
		}
		if (currentKeyCode==18){
			parent.setCurrentControlFunctionKey(Keyhandlers._CFK_ALT, System.currentTimeMillis());
		}
			
		if ((lastPanelKeyTime-System.currentTimeMillis()>150)){
			lastPanelKey = -1;
			lastPanelKeyTime = -1L;
		}
		// option note, that on PC keyboards it is the same as ctrl-alt 
		if ((lastPanelKey==524) && (lastPanelKeyTime>1000000) ){
			
			if ((new KeyCodes(evt.getKeyCode(),lastPanelKey)).is("q","option")){

			}
			
			parent.out.print(2, " --- detected : option key pressed ");

			if (System.currentTimeMillis() - lastKeyDetectTime<60){
				return;
			}
			lastKeyDetectTime = System.currentTimeMillis();		
			lastPanelKey = -1;
			lastPanelKeyTime = -1L;
			
		}

		
		// Shift
		if ((lastPanelKey==16) && (lastPanelKeyTime>1000000) && (lastPanelKeyTime-System.currentTimeMillis()<18)){
			
			return;
		}
		// Ctrl		
		if ((lastPanelKey==17) && (lastPanelKeyTime>1000000) && (lastPanelKeyTime-System.currentTimeMillis()<18)){
		
			// parent.out.print(2, " --- keyboard event : ctrl ");
			
			if ((new KeyCodes(evt.getKeyCode(),lastPanelKey)).is("w","ctrl")){
				// parent.out.print(2, " --- detected : Ctrl-w ");
			}
			if ((new KeyCodes(evt.getKeyCode(),lastPanelKey)).is("d","ctrl")){
				// parent.out.print(2, " --- detected : Ctrl-d ");
			}
			
			if ((new KeyCodes(evt.getKeyCode(),lastPanelKey)).is("x","ctrl")){
				elicitAction("ctrl-x", 999);
			}
			// ...............................................

		
			if (evt.getKeyCode()==68){
			
				elicitAction("ctrl-d", -1); // -1 -> the preset value (defined by constructor) will be used
				
				if (System.currentTimeMillis() - lastKeyDetectTime<60){
					return;
				}
				lastKeyDetectTime = System.currentTimeMillis();		
				lastPanelKey = -1;
				lastPanelKeyTime = -1L;
			}
			
			if (evt.getKeyCode()==87){
				
				elicitAction("ctrl-w", -1);

				if (System.currentTimeMillis() - lastKeyDetectTime<60){
					return;
				}
				
				
			}
			
			
			if ((evt.getKeyCode()>=37) && (evt.getKeyCode()<=40)){
				String arrow = getArrowFromCode();
				
				elicitAction("arrow", evt.getKeyCode()+1000);
			}


			// any function key ? externalize it...
			if ((evt.getKeyCode()>=112) && (evt.getKeyCode()<=123)){
				String fKey ;
				
				fKey = getFKeyFromCode(evt.getKeyCode());
				
				if ((new KeyCodes(evt.getKeyCode(),lastPanelKey)).is("f4","alt")){
					elicitAction("alt-f4", 999); 
				}
				
				
			}
			
			if (evt.getKeyCode()==88){
				// System.exit(0); not this way... application will not close due to running threads,  
				// we have to close them all through calling close() in main  
			}
			return;
		}
		// alt
		if ((lastPanelKey==18) && (lastPanelKeyTime>1000000) && (lastPanelKeyTime-System.currentTimeMillis()<18)){
		
			// parent.out.print(2, " --- keyboard event : alt ");

			if ((new KeyCodes(evt.getKeyCode(),lastPanelKey)).is("c","alt")){
				elicitAction("alt-c", 11); // clearing all panels
				return;
			}

			if ((new KeyCodes(evt.getKeyCode(),lastPanelKey)).is("d","alt")){
				elicitAction("alt-d", 30); // setting transparency
				return;
			}

			if ((new KeyCodes(evt.getKeyCode(),lastPanelKey)).is("r","alt")){
				elicitAction("alt-r", 32); // remove the selected panel (note, that the content will be removed, and all contents moved one up 
				return;
			}

			if ((new KeyCodes(evt.getKeyCode(),lastPanelKey)).is("h","alt")){
				elicitAction("alt-h", 40); // setting transparency
				return;
			}

			
			if (evt.getKeyCode()==87){
				
				if ((new KeyCodes(evt.getKeyCode(),lastPanelKey)).is("w","alt")){

					parent.out.print(2, " --- detected : Alt-w ");

					elicitAction("alt-w", 101); // get this from the global map or from config-callbacks  
								
					if (System.currentTimeMillis() - lastKeyDetectTime<60){
						return;
					}

					lastKeyDetectTime = System.currentTimeMillis();		
					lastPanelKey = 0;
					lastPanelKeyTime = -1L;
					return;
				}
			}
			
			if (evt.getKeyCode()==68){
				if ((new KeyCodes(evt.getKeyCode(),lastPanelKey)).is("d","alt")){
					parent.out.print(2, " --- detected : Alt-d ");
				}
				elicitAction("alt-d", 36);

				if (System.currentTimeMillis() - lastKeyDetectTime<60){
					return;
				}
				
				
			}

			if (evt.getKeyCode()==67){

				if ((new KeyCodes(evt.getKeyCode(),lastPanelKey)).is("c","alt")){
					parent.out.print(2, " --- detected : Alt-c ");
				}

				elicitAction("alt-c", 11);

				if (System.currentTimeMillis() - lastKeyDetectTime<60){
					return;
				}
				
				
			}

			return;
		} // alt

		if ((new KeyCodes(evt.getKeyCode(),lastPanelKey)).is("f1","")){
			elicitAction("f1", 0);
			
			return;
		}
		
		// only if no modifier is pressed, we will arrive here
		if ((evt.getKeyCode()>=37) && (evt.getKeyCode()<=40)){
			String arrow = getArrowFromCode();
			
		}

		lastPanelKey = evt.getKeyCode() ;
		lastPanelKeyTime = System.currentTimeMillis();
		
		
	}

	private String getFKeyFromCode( int code) {
		// 
		String fkeyStr = "f";
		
		fkeyStr = fkeyStr + (code-111);
		
		return fkeyStr;
	}
	
	private String getArrowFromCode() {
		// 
		return null;
	}
	private void elicitAction(String keybStr, int param) {
		// 
		
		parent.out.print(2, " --- detected :  "+keybStr+" ");
		
		if (actions.containsKey(keybStr)){
if (keybStr.contains("alt-c")){
	int k;
	k=0;
}
			((KeyActionIntf)actions.get(keybStr)).perform(param);
			
			lastKeyDetectTime = System.currentTimeMillis();		
			lastPanelKey = -1;
			lastPanelKeyTime = -1L;
		}else{
			parent.out.printErr(1,"KeyHandler::elicitAction() : No action found for keyboard command <"+keybStr+">");
			
			lastPanelKey = -1;
			lastPanelKeyTime = -1L;
		}
	
	}

	
	@Override
	public void setKeyListener(KeyListener keyListener) {
		// 
		
	}

	public void addAction(String key, KeyActionIntf keyAction ) {
		// 
		// will overwrite association if it exists
		actions.put( key , keyAction ) ;
	}

	/**
	 * 
	 * @param component
	 * @param windowAppearance
	 */
	public void attachGlobalKeys( Component component, 
								  WindowAppearanceIntf windowAppearance,
								  WindowAppearanceIntf resultsDisplayAgent) {
		// 
		int r;                                 // this needs a map !!!
		int param ;
		
		// FIXME no fixed programming here, loop through the map "parent.getGlobalKeyActionCodeMapping" , getting the keys!!!

		param = getActionMapParameter("f1");
		addAction("f1", (KeyActionIntf)(new WindowToggler(windowAppearance,param) ) );

		param = getActionMapParameter("alt-w"); 
		addAction("alt-w", (KeyActionIntf)(new WindowToggler(windowAppearance,param) ) ); // 1 = arbitrary parameter, later a param object!! untyped array or the like
		
		param = getActionMapParameter("alt-d");
		addAction("alt-d", (KeyActionIntf)(new WindowToggler(windowAppearance,param) ) );
		 
		param = getActionMapParameter("alt-c"); // clear=remove all panels
		addAction("alt-c", (KeyActionIntf)(new GuiWorkerRelais(resultsDisplayAgent,param) ) );

		param = getActionMapParameter("alt-r"); // clear=remove selected panels
		addAction("alt-r", (KeyActionIntf)(new GuiWorkerRelais(resultsDisplayAgent,param) ) );

		param = getActionMapParameter("alt-h"); // hide main status bar
		addAction("alt-h", (KeyActionIntf)(new GuiWorkerRelais(resultsDisplayAgent,param) ) );

		param = getActionMapParameter("ctrl-x");
		addAction("ctrl-x", (KeyActionIntf)(new GuiWorkerRelais(windowAppearance,param) ) );

		r = parent.getAppKeyListener().add( component, 1, this); 

	}
	private int getActionMapParameter(String keybStr) {
		// 
		int param =-1;
		
		if (parent.getGlobalKeyActionCodeMapping().containsKey(keybStr)){
			param = parent.getGlobalKeyActionCodeMapping().get(keybStr) ;
		}else{
			parent.out.printErr(3,"No global action mapping found for : "+keybStr);
		}
		return param ;
	}

}
